#include "GameMap.h"
#include "GameMain.h"
#include "GameRes.h"


GameMap::GameMap()
{
	_clickAni = nullptr;
}


GameMap::~GameMap()
{
	CC_SAFE_RELEASE_NULL(_clickAni);
	freeMap();
}

bool GameMap::init()
{
	if (!Node::init())
		return false;
	scheduleUpdate();

	_lBtnDown = false;
	_update = false;
	_layer = Layer::create();
	this->addChild(_layer);

	EventListenerMouse* mouse = EventListenerMouse::create();
	mouse->onMouseDown = [this](EventMouse* ev) {
		Vec2 point = this->convertToNodeSpace(ev->getLocation());
		switch (ev->getMouseButton()) {
		case EventMouse::MouseButton::BUTTON_LEFT:
			this->onMouseLButtionDown(point.x, point.y);
			break;
		case EventMouse::MouseButton::BUTTON_RIGHT:
			this->onMouseRButtionDown(point.x, point.y);
			break;
		}
	};
	mouse->onMouseUp = [this](EventMouse* ev) {
		Vec2 point = this->convertToNodeSpace(ev->getLocation());
		switch (ev->getMouseButton()) {
		case EventMouse::MouseButton::BUTTON_LEFT:
			this->onMouseLButtionUp(point.x, point.y);
			break;
		case EventMouse::MouseButton::BUTTON_RIGHT:
			this->onMouseRButtionUp(point.x, point.y);
			break;
		}
	};
	Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(mouse, this);
	this->setPosition(Vec2::ZERO);

	auto wFile = ResManager::GetInstance()->GetWDFFile(0x0D98AC0A);
	if (wFile) {
		XY_Was was;
		if (was.Load(wFile.pData, wFile.size, true)) {
			const auto* pHeader = was.GetHeader();
			const auto* pFrames = was.GetFrames();

			Vector<SpriteFrame*> frames;

			int nFrame = pHeader->numFrame;
			for (int i = 0;i < nFrame;++i) {
				const auto* pInfo = &pFrames[i];
				auto* img = new Image;
				img->initWithImageData(pInfo->clrTable, pInfo->size);
				img->autorelease();
				auto* tex = new Texture2D;
				tex->initWithImage(img);
				tex->autorelease();
				auto* sprFrame = SpriteFrame::createWithTexture(tex, Rect(Vec2::ZERO, Size(pInfo->header.width, pInfo->header.height)));
				sprFrame->setAnchorPoint(Vec2((float)pInfo->header.centerX / (float)pInfo->header.width, 1.0f - (float)pInfo->header.cneterY / (float)pInfo->header.height));
				frames.pushBack(sprFrame);
			}
			_clickAni = new Animate;
			_clickAni->initWithAnimation(Animation::createWithSpriteFrames(frames, 5.0f / CONFIG_FPS));
		}
	}
	return true;
}

void GameMap::update(float dt)
{
	if (_lBtnDown) {
		if (_lBtnDelta < 5)_lBtnDelta += dt;
		if (_lDelta > 0) {
			_lDelta -= dt;
		}
		else if (_lBtnDelta >= 1.0f) {
			_lDelta = 0.066f;
			Vec2 pos = GameMain::GetMouse()->getPosition();
			auto vSize = Director::getInstance()->getVisibleSize();
			onMouseLButtionUp(pos.x, vSize.height - pos.y);
		}
	}

	if (!_update) {
		int posX = GameMain::GetPlayer()->GetPosX();
		int posY = GameMain::GetPlayer()->GetPosY();

		auto visibleSize = Director::getInstance()->getVisibleSize();
		Vec2 origin = Director::getInstance()->getVisibleOrigin();

		const auto* info = _map.GetInfo();
		bool edgeX = info->width < visibleSize.width;
		bool edgeY = info->height < visibleSize.height;

		int mapX = 0, mapY = info->height;
		if (!edgeX) {
			mapX = posX * 20 + 10;
			int centerX = visibleSize.width / 2;
			mapX -= centerX;
			if (mapX < 0) {
				mapX = 0;
				edgeX = true;
			}
			else if (mapX + centerX > info->width) {
				mapX = info->width - visibleSize.width;
				edgeX = true;
			}
		}
		if (!edgeY) {
			mapY = posY * 20 + 10;
			int centerY = visibleSize.height / 2;
			mapY += centerY;
			if (mapY - visibleSize.height < 0) {
				mapY = visibleSize.height;
				edgeY = true;
			}else if (mapY > info->height) {
				mapY = info->height;
				edgeY = true;
			}
		}
		
		int idxRow = (info->height - mapY) / info->blockHeight;
		int colOffset = (info->height - mapY) % info->blockHeight;
		int idxCol = mapX / info->blockWidth;
		int rowOffset = mapX % info->blockWidth;

		int rowSpr = 3;while ((info->blockWidth - rowOffset + (rowSpr-1)*info->blockWidth) < visibleSize.width)++rowSpr;
		int colSpr = 3;while (visibleSize.height - (info->blockHeight - colOffset + (colSpr-1)*info->blockHeight) > 0)++colSpr;
		if (rowSpr > info->blockOfRow)rowSpr = info->blockOfRow;
		if (colSpr > info->blockOfCol)colSpr = info->blockOfCol;
		for (int col = 0;col < colSpr;++col) {
			for (int row = 0;row < rowSpr;++row) {
				std::string key = StringUtils::format("m_%d_%d", col * info->blockOfRow + idxRow, row + idxCol);
				auto* tex = Director::getInstance()->getTextureCache()->getTextureForKey(key);
				if (!tex) {
					auto* img = getImage((info->blockOfRow*(col + idxRow)) + (row + idxCol));
					img->autorelease();
					tex = Director::getInstance()->getTextureCache()->addImage(img, key);
					tex->autorelease();
				}
				Sprite* spr = Sprite::createWithTexture(tex);
				_layer->addChild(spr, 0, row * 10 + col);
				spr->setPosition(Vec2(row * 320 - rowOffset, visibleSize.height - col * 240 + colOffset));
				spr->setAnchorPoint(Point::ANCHOR_TOP_LEFT);
			}
		}
		_leftPos = idxCol*info->blockWidth + rowOffset;
		_topPos = info->height - (idxRow*info->blockHeight + colOffset);
		_update = true;
		
		DrawNode* drawNode = DrawNode::create(2);
		_layer->addChild(drawNode);
		for (int row = 0;row < rowSpr;++row) {
			for(int col=0;col<colSpr;++col){
				auto* spr=(Sprite*)_layer->getChildByTag(row * 10 + col);
				auto rc = spr->getBoundingBox();
				drawNode->drawRect(rc.origin, rc.origin+rc.size, Color4F::RED);
			}
		}
	}
}

void GameMap::onMouseLButtionDown(int x, int y)
{
	_lBtnDelta = 0;
	_lDelta = 0;
	_lBtnDown = true;
}

void GameMap::onMouseLButtionUp(int x, int y)
{
	if (_lBtnDelta < 1.0f) {
		_lBtnDown = false;
	}
	Vec2 pos = viewToWorld(x, y);
	std::string str = StringUtils::format("X:%.f Y:%.f\r\n", pos.x, pos.y);
	OutputDebugString(str.c_str());
	auto vSize = Director::getInstance()->getVisibleSize();
	auto* spr = Sprite::create();

	pos = _layer->convertToNodeSpace(Vec2(x,y));
	str = StringUtils::format("X:%.f Y:%.f\r\nX:%d Y:%d >>>>\r\n", pos.x, pos.y,x,y);
	OutputDebugString(str.c_str());

	spr->setPosition(x, vSize.height - y);
	_layer->addChild(spr);
	spr->runAction(Sequence::create(_clickAni->clone(), CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, spr)), nullptr));

// 	pos = _layer->getPosition();
// 	pos.y += 20;
// 	auto* t = MoveTo::create(1, pos);
// 	_layer->runAction(t);
}

void GameMap::onMouseRButtionDown(int x, int y)
{

}

void GameMap::onMouseRButtionUp(int x, int y)
{

}

Vec2 GameMap::viewToWorld(int x, int y)
{
	int posX = _leftPos + x;
	int posY = _topPos - y;
	x = posX / 20;
	y = posY / 20;
	return Vec2(x, y);
}

Vec2 GameMap::worldToView(int x, int y)
{
	auto vSize = Director::getInstance()->getVisibleSize();
	int posX = x * 20 - _leftPos;
	int posY = vSize.height - (_topPos - y * 20);
	return Vec2(posX, posY);
}

bool GameMap::loadMap(const char* fileName)
{
	return _map.LoadMap(fileName);
}

void GameMap::freeMap(void)
{
	auto* pInfo = _map.GetInfo();
	auto* texCache = Director::getInstance()->getTextureCache();
	for (uint32_t row = 0;row < pInfo->blockOfRow;++row) {
		for (uint32_t col = 0;col < pInfo->blockOfCol;++col) {
			std::string key = StringUtils::format("m_%d_%d", row, col);
			texCache->removeTextureForKey(key);
		}
	}
	_map.FreeMap();
}

cocos2d::Image* GameMap::getImage(uint32_t index)
{
	uint32_t length;
	const void* pImage = _map.GetImage(index, &length);
	if (pImage) {
		Image* img = new Image;
		if (img->initWithImageData((const unsigned char*)pImage, length))
			return img;
		delete img;
	}
	return nullptr;
}

bool GameMap::playerMove(int x, int y)
{
	return true;
}